// Ninf-G-XX, ver. 0.1
// Copyright 2011 National Institute of Advanced Industrial Science and Technology
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "Ninf.h"
#include "Global.hpp"
#include "Session.hpp"
#include "CallException.hpp"

using namespace ninf::client;

NinfErrorCode 
NinfCall   (
  const char * entry, 
  ...
){
  NinfErrorCode errorCode;
  Session * session;
  va_list ap;
  try {
    fprintf(stderr, "try to create Session\n");
    session = new Session(entry, true);
  } catch (CallException e) {
    return e.errorCode;
  }

  va_start(ap, entry);
  errorCode = session->invoke(ap);
  va_end(ap);
  if (errorCode != NINF_NO_ERROR)
    return errorCode;

  try {
    Global::global.sessionManager.wait(session->id);
  } catch (Exception e) {
    cerr << e;
    return NINF_INTERNAL_ERROR;
  }
  return NINF_NO_ERROR;
}

NinfErrorCode 
NinfCallAsync   (
  const char * entry, 
  NinfSessionId * pSessionId,
  ...
){
  NinfErrorCode errorCode;
  Session * session;
  va_list ap;
  try {
    fprintf(stderr, "try to create Session\n");
    session = new Session(entry, true);
  } catch (CallException e) {
    return e.errorCode;
  }

  va_start(ap, pSessionId);
  errorCode = session->invoke(ap);
  va_end(ap);
  if (errorCode != NINF_NO_ERROR)
    return errorCode;
  * pSessionId = session->id;
  
  return NINF_NO_ERROR;
}


/************************* WAIT FUNCTIONS ************************/

NinfErrorCode
NinfWait(NinfSessionId id){
  try {
    Global::global.sessionManager.wait(id);
  } catch (Exception e) {
    cerr << e;
    return NINF_INTERNAL_ERROR;
  }
  return NINF_NO_ERROR;
}


NinfErrorCode
NinfWaitAll(){
  try {
    Global::global.sessionManager.waitAll();
  } catch (Exception e) {
    cerr << e;
    return NINF_INTERNAL_ERROR;
  }
  return NINF_NO_ERROR;
}
NinfErrorCode
NinfWaitAny(NinfSessionId * id){
  try {
    *id = Global::global.sessionManager.waitAny();
  } catch (Exception e) {
    cerr << e;
    return NINF_INTERNAL_ERROR;
  }
  return NINF_NO_ERROR;
}

NinfErrorCode
NinfWaitAnd(NinfSessionId * idList, int length){
  try {
    Global::global.sessionManager.waitAnd(idList, length);
  } catch (Exception e) {
    cerr << e;
    return NINF_INTERNAL_ERROR;
  }
  return NINF_NO_ERROR;
}

NinfErrorCode
NinfWaitOr(NinfSessionId * idList, int length, NinfSessionId * id){
  try {
    *id = Global::global.sessionManager.waitOr(idList, length);
  } catch (Exception e) {
    cerr << e;
    return NINF_INTERNAL_ERROR;
  }
  return NINF_NO_ERROR;
}


/************************* STATUS, CANCEL ************************/

NinfErrorCode
NinfCancel(NinfSessionId id){
  try {
    Global::global.sessionManager.cancel(id);
  } catch (Exception e) {
    cerr << e;
    return NINF_INTERNAL_ERROR;
  }
  return NINF_NO_ERROR;
}

NinfErrorCode
NinfCancelAll(){
  try {
    Global::global.sessionManager.cancelAll();
  } catch (Exception e) {
    cerr << e;
    return NINF_INTERNAL_ERROR;
  }
  return NINF_NO_ERROR;
}

NinfErrorCode
NinfProbe(NinfSessionId id){
  try {
			if (Global::global.sessionManager.probe(id))
					return NINF_NO_ERROR;
			else
					return NINF_NON_COMPLETED;
  } catch (Exception e) {
    cerr << e;
    return NINF_INTERNAL_ERROR;
  }
  return NINF_NO_ERROR;
}

NinfErrorCode
NinfProbeOr(NinfSessionId * idList, int length, NinfSessionId * id){
  try {
			if (Global::global.sessionManager.probeOr(idList, length, id))
					return NINF_NO_ERROR;
			else
					return NINF_NON_COMPLETED;
  } catch (Exception e) {
    cerr << e;
    return NINF_INTERNAL_ERROR;
  }
  return NINF_NO_ERROR;
}


NinfErrorCode
NinfGetInfo(
  NinfSessionId   id, 
  ExecInfo    * info
){
  Session * session = Global::global.sessionManager.getSession(id);
  if (session == NULL)
    return NINF_INTERNAL_ERROR;
  info->status = session->status;
  info->code   = session->errorCode;
  return NINF_NO_ERROR;
}


/************************* INIT, FINAILIZE ************************/

/// initialize function for NinfAPI
int 
NinfParseArg(
  int     argc,
  char ** argv
){
  return Global::global.parseArg(argc, argv);
}

/// finalize function for NinfAPI
NinfErrorCode
NinfFinalize()
{
  return NINF_NO_ERROR;
}

/****** ErrorHandle *********/
NinfErrorCode
NinfPerror(const char * str){
  try {
    Global::global.sessionManager.perror(str, stderr);
  } catch (Exception e) {
    cerr << e;
    return NINF_INTERNAL_ERROR;
  }
  return NINF_NO_ERROR;
}

NinfErrorCode
NinfGetError(NinfSessionId id) {
		return Global::global.sessionManager.getSession(id)->errorCode;
}

NinfErrorCode
NinfGetFailedSessionID(NinfSessionId * idP) {
		Global::global.sessionManager.getFailedSessionID(idP);
		return NINF_NO_ERROR;
}
